package com.test.monitor;

import java.io.File;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Timer;
import java.util.TimerTask;

/**
 ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
 * Description: 
 * Author: Heller (HellerSong@outlook.com)
 * CreationTime: Apr 11, 2015
 ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
 **/
public class FileMonitor {

	private Timer timer;
	private HashMap<File, Long> allFiles;
	private Collection<WeakReference<FileListener>> allListeners;

	public FileMonitor(long pollingInterval) {
		allFiles = new HashMap<File, Long>();
		allListeners = new ArrayList<WeakReference<FileListener>>();
		timer = new Timer(true);
		timer.schedule(new FileMonitorNotifier(), 0, pollingInterval);
	}

	public void addFile(File file) {
		if (!allFiles.containsKey(file)) {
			long modifiedTime = file.exists() ? file.lastModified() : -1;
			allFiles.put(file, new Long(modifiedTime));
		}
	}

	public void removeFile(File file) {
		allFiles.remove(file);
	}

	public void addListener(FileListener fileListener) {
		for (Iterator<WeakReference<FileListener>> i = allListeners.iterator(); i.hasNext();) {
			WeakReference<?> reference = (WeakReference<?>) i.next();
			FileListener listener = (FileListener) reference.get();
			if (listener == fileListener)
				return;
		}
		allListeners.add(new WeakReference<FileListener>(fileListener));
	}

	public void removeListener(FileListener fileListener) {
		for (Iterator<WeakReference<FileListener>> i = allListeners.iterator(); i.hasNext();) {
			WeakReference<?> reference = (WeakReference<?>) i.next();
			FileListener listener = (FileListener) reference.get();
			if (listener == fileListener) {
				i.remove();
				break;
			}
		}
	}

	public void stop() {
		timer.cancel();
	}

	private class FileMonitorNotifier extends TimerTask {
		@Override
		public void run() {
			Collection<File> files = new ArrayList<File>(allFiles.keySet());
			for (Iterator<File> i = files.iterator(); i.hasNext();) {
				File file = (File) i.next();
				long lastModifiedTime = allFiles.get(file).longValue();
				long newModifiedTime = file.exists() ? file.lastModified() : -1;
				if (newModifiedTime != lastModifiedTime) {
					allFiles.put(file, new Long(newModifiedTime));
					for (Iterator<WeakReference<FileListener>> j = allListeners.iterator(); j.hasNext();) {
						WeakReference<?> reference = (WeakReference<?>) j.next();
						FileListener listener = (FileListener) reference.get();
						// Remove from list if the backend object has been GC'd
						if (listener == null)
							j.remove();
						else
							listener.fileChanged(file);
					}
				}
			}
		}
	}

}
